﻿using Engine;
using Engine.Graphics;
using System.Collections.Generic;
using System.Linq;
using Game;

namespace MMap
{
	public class MMapFrameBlock : Block
	{
		public BlockMesh m_standaloneBlockMesh = new();
		public BlockMesh[] m_blockMesh = new BlockMesh[4];
		public Texture2D m_texture;
		public Texture2D m_texture2;

		public BoundingBox[][] m_collisionBoxes = new BoundingBox[4][];

		public override void Initialize()
		{
			Model model = ContentManager.Get<Model>("Models/MMapFrame");
			m_texture = ContentManager.Get<Texture2D>("Textures/Items/MMapFrame");
			m_texture2 = ContentManager.Get<Texture2D>("Textures/Items/MMapFrame_Map");
			Matrix boneAbsoluteTransform = BlockMesh.GetBoneAbsoluteTransform(model.FindMesh("Rack").ParentBone);
			m_standaloneBlockMesh.AppendModelMeshPart(model.FindMesh("Rack").MeshParts[0], boneAbsoluteTransform * Matrix.CreateTranslation(0f, -0.5f, 0f), false, false, false, false, Color.White);
			for (int i = 0; i < 4; i++)
			{
				float angle = MathUtils.DegToRad(i * 90f);
				m_blockMesh[i] = new BlockMesh();
				var blockMesh = new BlockMesh();
				blockMesh.AppendModelMeshPart(model.FindMesh("Rack").MeshParts[0], boneAbsoluteTransform * Matrix.CreateRotationY(angle) * Matrix.CreateTranslation(0.5f, 0f, 0.5f), false, false, false, false, Color.White);
				m_blockMesh[i].AppendBlockMesh(blockMesh);
				m_collisionBoxes[i] = [blockMesh.CalculateBoundingBox()];
			}
			base.Initialize();
		}

		public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z)
		{
			int rotation = MathUtils.Clamp(GetRotation(Terrain.ExtractData(value)), 0, 3);
			int mapData = GetMapData(Terrain.ExtractData(value));
			generator.GenerateMeshVertices(this, x, y, z, m_blockMesh[rotation], Color.White, null, geometry.GetGeometry(mapData > 0 ? m_texture2 : m_texture).SubsetOpaque);
		}

		public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData)
		{
			BlocksManager.DrawMeshBlock(primitivesRenderer, m_standaloneBlockMesh, m_texture, color, size, ref matrix, environmentData);
		}

		public override BoundingBox[] GetCustomCollisionBoxes(SubsystemTerrain terrain, int value)
		{
			int data = MathUtils.Clamp(GetRotation(Terrain.ExtractData(value)), 0, 3);
			return m_collisionBoxes[data];
		}

		public override BlockPlacementData GetPlacementValue(SubsystemTerrain subsystemTerrain, ComponentMiner componentMiner, int value, TerrainRaycastResult raycastResult)
		{
			int rotation = 0;
			int face = raycastResult.CellFace.Face;
			if (face >= 4)
			{//点击顶面或底面
				Vector3 forward = Matrix.CreateFromQuaternion(componentMiner.ComponentCreature.ComponentCreatureModel.EyeRotation).Forward;
				float num = Vector3.Dot(forward, Vector3.UnitZ);
				float num2 = Vector3.Dot(forward, Vector3.UnitX);
				float num3 = Vector3.Dot(forward, -Vector3.UnitZ);
				float num4 = Vector3.Dot(forward, -Vector3.UnitX);
				if (num == MathUtils.Max(num, num2, num3, num4))
					rotation = 0;
				else if (num2 == MathUtils.Max(num, num2, num3, num4))
					rotation = 1;
				else if (num3 == MathUtils.Max(num, num2, num3, num4))
					rotation = 2;
				else if (num4 == MathUtils.Max(num, num2, num3, num4))
					rotation = 3;
			}
			else
			{
				rotation = (face + 2) % 4;
			}
			BlockPlacementData result = new()
			{
				Value = Terrain.MakeBlockValue(BlocksManager.GetBlockIndex<MMapFrameBlock>(), 0, SetRotation(0, rotation)),
				CellFace = raycastResult.CellFace
			};
			return result;
		}

		public override void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List<BlockDropValue> dropValues, out bool showDebris)
		{
			showDebris = true;
			dropValues.Add(new BlockDropValue
			{
				Value = BlocksManager.GetBlockIndex<MMapFrameBlock>(),
				Count = 1
			});
			int mapData = GetMapData(Terrain.ExtractData(oldValue));
			if (mapData > 0)
			{
				var item = new BlockDropValue
				{
					Value = Terrain.MakeBlockValue(BlocksManager.GetBlockIndex<MMapBlock>(), 0, mapData),
					Count = 1
				};
				dropValues.Add(item);
			}
		}

		//101..  11
		//二进制后两位为旋转值，其他都是地图data
		public static int GetRotation(int data)
		{
			return data % 4;
		}
		public static int SetRotation(int data, int rotation)
		{
			return data - data % 4 + rotation;
		}

		public static int GetMapData(int data)
		{
			return (data - data % 4) / 4;
		}

		public static int SetMapData(int data, int mapData)
		{
			return mapData * 4 + data % 4;
		}
	}
}
